#[allow(unused_imports)]
use std::{
    time::{Duration,Instant},
    thread, sync::{Arc,atomic::*},
};
use crate::{defines::*};

pub mod lock_free_dt {
    use crate::lock_free;
    pub use lock_free::queue::Queue;
    pub use lock_free::hashmap::UltraHashMap;
    pub use lock_free::list::IndexedList;
    pub use lock_free::list::UnorderedSet;
}

pub struct FrameSync {
    time_begin: Instant,
    frame_spac: Duration,
}
impl FrameSync {
    pub fn new(frame_spac:Duration) -> Self {
        Self {time_begin: Instant::now(), frame_spac}
    }
    pub fn with_ms(ms:usize) -> Self {
        Self::new(Duration::from_millis(ms as u64))
    }
    #[inline] pub fn clock_now(&mut self) -> &mut Self {
        self.time_begin = Instant::now();
        self
    }
    #[inline] pub fn sync(&mut self) {
        let frame_elapsed = self.time_begin.elapsed();
        if frame_elapsed < self.frame_spac {
            thread::sleep(self.frame_spac - frame_elapsed);
        }
        self.time_begin = Instant::now();
    }
}

#[derive(Debug)]
pub struct ByteReader<'a> {
    bytes:&'a [u8],
    cursor: usize,
}

impl<'a> ByteReader<'a> {
    pub fn from(bytes:&'a [u8]) -> Self {
        Self {bytes, cursor:0}
    }
    #[inline] pub fn have(&self) -> bool {
        self.cursor < self.bytes.len()
    }
    #[inline] pub fn remsize(&self) -> usize {
        self.bytes.len() - self.cursor
    }
    #[inline] pub fn seek(&mut self, to:usize) -> &mut Self {
        self.cursor = to.clamp(0, self.bytes.len());
        self
    }
    #[inline] pub fn cursor(&self) -> usize {
        self.cursor
    }
    #[inline] pub fn get(&mut self, size:usize) -> &'a [u8] {
        debug_assert!(self.remsize() >= size);
        let bytes = &self.bytes[self.cursor .. (size + self.cursor)];
        self.seek(self.cursor + size);
        bytes
    }
}

pub trait ByteRead {
    fn from_bytes(bytes:&[u8]) -> Result<Self> where Self: Sized {
        let mut reader = ByteReader::from(bytes);
        Self::from_bytereader(&mut reader)
    }
    fn from_bytereader(reader:&mut ByteReader) -> Result<Self> where Self: Sized;
}

macro_rules! _BYTEREAD_TO {
    ($T:ty) => {
        impl ByteRead for $T {
            fn from_bytes(bytes:&[u8]) -> Result<Self> {
                Ok(<$T>::from_be_bytes(bytes.try_into()?))
            }
            fn from_bytereader(reader:&mut ByteReader) -> Result<Self> {
                Ok(<$T>::from_be_bytes(reader.get(size_of::<Self>()).try_into()?))
            }
        }
    };
}
_BYTEREAD_TO!(u8);
_BYTEREAD_TO!(u16);
_BYTEREAD_TO!(u32);
_BYTEREAD_TO!(u64);
_BYTEREAD_TO!(u128);
_BYTEREAD_TO!(usize);
_BYTEREAD_TO!(i8);
_BYTEREAD_TO!(i16);
_BYTEREAD_TO!(i32);
_BYTEREAD_TO!(i64);
_BYTEREAD_TO!(i128);
_BYTEREAD_TO!(isize);
_BYTEREAD_TO!(f32);
_BYTEREAD_TO!(f64);
impl ByteRead for String {
    fn from_bytereader(reader:&mut ByteReader) -> Result<Self> {
        let bytes = reader.bytes;
        let first = reader.cursor;
        let mut last = reader.cursor;
        let mut trim_zero = false;
        while last < bytes.len() {
            let c = bytes[last];
            last += 1;
            if 0 == c {
                trim_zero = true; break
            }
        }
        reader.seek(last);
        let last = if trim_zero {last - 1} else {last};
        Ok(String::from_utf8_lossy(&bytes[first..last]).to_string())
    }
}

#[derive(Debug)]
pub struct ByteWriter {
    bytes:Vec<u8>,
}

impl ByteWriter {
    pub fn new () -> Self {
        Self {bytes: Vec::new()}
    }
    pub fn with_capacity(init_capacity:usize) -> Self {
        Self {bytes: Vec::with_capacity(init_capacity)}
    }
    #[inline] pub fn size(&self) -> usize {
        self.bytes.len()
    }
    #[inline] pub fn bytes(&self) -> &[u8] {
        &self.bytes
    }
    #[inline] pub fn clear(&mut self) -> &mut Self {
        self.bytes.clear();
        self
    }
    pub fn fill_to(&mut self, end_offset:usize, val:u8) -> &mut Self {
        if self.size() < end_offset {
            let mut rest:Vec<u8> = Vec::new();
            rest.resize(end_offset - self.size(), val);
            self.bytes.extend_from_slice(&rest[..]);
        }
        self
    }
    #[inline] pub fn fill_rest(&mut self, val:u8) -> &mut Self {
        self.fill_to(self.bytes.capacity(), val)
    }
    #[inline] pub fn _put(&mut self, bytes:&[u8]) -> &mut Self {
        self.bytes.extend_from_slice(bytes);
        self
    }
}

pub trait ByteWrite {
    fn to_bytes(&self) -> Vec<u8> {
        let mut writer = ByteWriter::new();
        self.to_bytewriter(&mut writer).unwrap();
        writer.bytes.to_vec()
    }
    fn to_bytewriter(&self, writer:&mut ByteWriter) -> Result<()>;
}

macro_rules! _BYTEWRITE_FROM {
    ($T:ty) => {
        impl ByteWrite for $T {
            fn to_bytes(&self) -> Vec<u8> {
                self.to_be_bytes().to_vec()
            }
            fn to_bytewriter(&self, writer:&mut ByteWriter) -> Result<()> {
                writer._put(&(self.to_be_bytes()));
                Ok(())
            }
        }
    };
}
_BYTEWRITE_FROM!(u8);
_BYTEWRITE_FROM!(u16);
_BYTEWRITE_FROM!(u32);
_BYTEWRITE_FROM!(u64);
_BYTEWRITE_FROM!(u128);
_BYTEWRITE_FROM!(usize);
_BYTEWRITE_FROM!(i8);
_BYTEWRITE_FROM!(i16);
_BYTEWRITE_FROM!(i32);
_BYTEWRITE_FROM!(i64);
_BYTEWRITE_FROM!(i128);
_BYTEWRITE_FROM!(isize);
_BYTEWRITE_FROM!(f32);
_BYTEWRITE_FROM!(f64);
impl ByteWrite for String {
    fn to_bytewriter(&self, writer:&mut ByteWriter) -> Result<()> {
        writer._put(self.as_bytes())._put(&[0u8]);
        Ok(())
    }
}
impl ByteWrite for [u8] {
    fn to_bytewriter(&self, writer:&mut ByteWriter) -> Result<()> {
        writer._put(&self);
        Ok(())
    }
}

pub fn normalize(s:&[f32]) -> Vec<f32> {
    let mut min:f32 = s[0];
    let mut max:f32 = s[0];
    for a in s {
        if *a < min {min = *a}
        else if *a > max {max = *a}
    }
    let fuck = max - min;
    s.iter().map(|a|{(*a - min) / fuck}).collect()
}

#[cfg(test)]
pub mod pftest {
    use super::*;

    pub fn once<F:FnMut()>(mut fn_run:F) -> Duration {
        let time_start = Instant::now();
        fn_run();
        time_start.elapsed()
    }

    #[allow(dead_code)]
    #[derive(Debug,Copy,Clone,Default)]
    pub struct BatchResult {
        all: Duration,
        avg: Duration,
        min: Duration,
        max: Duration,
    }
    #[allow(dead_code)]
    pub fn batch<F:FnMut()+Copy>(fn_run:F, n_batch:usize) -> BatchResult {
        assert!(n_batch > 0);
        let time_all = Instant::now();
        let mut avg:Duration = once(fn_run);
        let mut time_min = avg;
        let mut time_max = avg;
        for _ in 1..n_batch {
            let time_once = once(fn_run);
            if time_once < time_min {
                time_min = time_once;
            } else if time_once > time_max {
                time_max = time_max;
            }
            avg = (avg + time_once) / 2;
        }
        BatchResult { all: time_all.elapsed(), avg, min: time_min, max: time_max }
    }
    #[allow(dead_code)]
    pub fn batch_mt<F:FnMut()+Copy+Send + 'static>(fn_run:F, n_batch:usize, n_task:usize) -> BatchResult {
        assert!(n_batch > 0);
        assert!(n_task > 0);
        // let avg_batch = n_batch / n_task;
        // let remain_num = n_batch % n_task;
        // let results:Arc<Vec<BatchResult>> = Arc::new(Vec::new());
        // let n_done:Arc<atomic::AtomicUsize> = Arc::new(AtomicUsize::new(0));
        // results.resize(n_task, Default::default());
        // let time_start = Instant::now();
        // let _1 = Arc::clone(&n_done);
        // thread::spawn(move ||{
        //     results[0] = batch(fn_run, avg_batch+remain_num);
        //     _1.fetch_add(1, Ordering::Relaxed);
        // });
        // for i in 1..n_task {
        //     thread::spawn(move || {
        //         results[i] = batch(fn_run, avg_batch);
        //         n_done.fetch_add(1, Ordering::Relaxed);
        //     });
        // }
        // while n_done.load(Ordering::Relaxed) < n_task {thread::sleep(Duration::from_micros(100));}
        // let avg = results.iter().fold(Duration::default(), |n,a|{n + a.avg}) / n_task as u32;
        // let min = results.iter().map(|a|{a.min}).min().unwrap();
        // let max = results.iter().map(|a|{a.max}).max().unwrap();
        // BatchResult { all:time_start.elapsed(), avg, min, max}
        BatchResult::default()
    }
    #[allow(dead_code)]
    pub fn batch_mt_auto<F:FnMut()+Copy+Send + 'static>(fn_run:F, n_batch:usize) -> BatchResult {
        batch_mt(fn_run, n_batch, 8)
    }

    #[allow(dead_code)]
    #[derive(Debug,Copy,Clone,Default)]
    pub struct PerTime {
        n_task: usize,
        all: Duration,
        avg: Duration,
        min: Duration,
        max: Duration,
    }
    #[allow(dead_code)]
    pub fn per_time<F:FnMut()+Copy+Send + 'static>(fn_run:F, max_time:Duration) -> PerTime {
        assert!(max_time.as_secs() > 0);
        let time_all = Instant::now();
        let mut avg:Duration = once(fn_run);
        let mut time_min = avg;
        let mut time_max = avg;
        let mut n_task = 0;
        while time_all.elapsed() < max_time {
            let time_once = once(fn_run);
            if time_once < time_min {
                time_min = time_once;
            } else if time_once > time_max {
                time_max = time_max;
            }
            avg = (avg + time_once) / 2;
            n_task += 1;
        }
        PerTime { all: time_all.elapsed(), avg, min: time_min, max: time_max , n_task}
    }
}
